unit uBasePage;

interface
uses
  GlScene,
  Classes;
//------------------------------------------------------------------------------
type
  TPageState = (stShow, stHide, stShowing, stHiding);
  TBasePage = class;
  TBasePageEvent = Procedure (aPage: TBasePage) of object;
//------------------------------------------------------------------------------
  TBasePage = class
  protected
    fUnitTime: Single; // from 0 to 1
    fShowSpeed: Single;
    fHideSpeed: Single;

    fCurrentState: TPageState;
    fFinishState: TPageState;
    fOnShowComplete: TBasePageEvent;
    fOnHideComplete: TBasePageEvent;
  protected
    Procedure HideStep(aDeltaTime: Single); virtual;
    Procedure ShowStep(aDeltaTime: Single); virtual;
    Procedure HideComplete(); virtual;
    Procedure UpdateUnitTime(); virtual;
  public
    property OnShowComplete: TBasePageEvent read fOnShowComplete write fOnShowComplete;
    property OnHideComplete: TBasePageEvent read fOnHideComplete write fOnHideComplete;
    Function IsVisible: Boolean;
    Procedure Show; virtual;
    Procedure ForcedShow; virtual;
    Procedure Hide; virtual;
    Procedure Update(aDeltaTime: Single); virtual;
    Constructor Create();
  end;
//------------------------------------------------------------------------------
  TBasePageClass = class of TBasePage;

  TPageList = class(TList)
  public
    Function GetPageByIndex(aPageIndex: Integer): TBasePage;
    Function GetPageByClass(aPageClass: TBasePageClass): TBasePage;
    Function AddPageByClass(aPageClass: TBasePageClass): TBasePage;
    Function GetIndexByClass(aPageClass: TBasePageClass): Integer;
    Function DeletePageByClass(aPageClass: TBasePageClass; aShouldFree: Boolean = false): Boolean;
    Function DeletePage(var aPage: TBasePage; aShouldFree: Boolean = false): Boolean;
  end;
//------------------------------------------------------------------------------
implementation
uses
  SysUtils;
//------------------------------------------------------------------------------
Procedure TBasePage.HideStep(aDeltaTime: Single);
begin
  fUnitTime := fUnitTime - fShowSpeed * aDeltaTime;
  if fUnitTime <= 0 then
  begin
    fUnitTime := 0;
    fCurrentState := stHide;
    HideComplete();
  end;
end;
//------------------------------------------------------------------------------
Procedure TBasePage.ShowStep(aDeltaTime: Single);
begin
  fUnitTime := fUnitTime + fShowSpeed * aDeltaTime;
  if fUnitTime >= 1 then
  begin
    fUnitTime := 1;
    fCurrentState := stShow;
  end;
end;
//------------------------------------------------------------------------------
Procedure TBasePage.HideComplete();
begin
  if Assigned(OnHideComplete) then
    OnHideComplete(self);
end;
//------------------------------------------------------------------------------
Procedure TBasePage.UpdateUnitTime();
begin
end;
//------------------------------------------------------------------------------
Function TBasePage.IsVisible: Boolean;
begin
  result := (fFinishState = stShow) or (fFinishState = stShowing);
end;
//------------------------------------------------------------------------------
Procedure TBasePage.Show;
begin
  fFinishState := stShow;
end;
//------------------------------------------------------------------------------
Procedure TBasePage.ForcedShow;
begin
end;
//------------------------------------------------------------------------------
Procedure TBasePage.Hide;
begin
  fFinishState := stHide;
end;
//------------------------------------------------------------------------------
Procedure TBasePage.Update(aDeltaTime: Single);
begin
  if fFinishState <> fCurrentState then
  begin
    if fFinishState = stShow then
    begin
      fCurrentState := stShowing;
      ShowStep(aDeltaTime);
    end
    else if fFinishState = stHide then
    begin
      fCurrentState := stHiding;
      HideStep(aDeltaTime);
    end;

    UpdateUnitTime();
  end;
end;
//------------------------------------------------------------------------------
Constructor TBasePage.Create();
begin
  fCurrentState := stHide;
  fFinishState := stHide;
  fUnitTime := 0;
  fShowSpeed := 1;
  fHideSpeed := 1;
end;
//------------------------------------------------------------------------------
Function TPageList.GetPageByIndex(aPageIndex: Integer): TBasePage;
begin
  if (aPageIndex >= 0) and (aPageIndex < Count) then
    result := TBasePage(Items[aPageIndex])
  else
    result := nil;  
end;
//------------------------------------------------------------------------------
Function TPageList.GetPageByClass(aPageClass: TBasePageClass): TBasePage;
var
  PageIndex: Integer;
begin
  PageIndex := GetIndexByClass(aPageClass);
  if PageIndex > -1 then
    result := TBasePage(Items[PageIndex])
  else
    result := nil;
end;
//------------------------------------------------------------------------------
Function TPageList.GetIndexByClass(aPageClass: TBasePageClass): Integer;
var
  i: integer;
begin
  result := -1;

  for i := 0 to Count - 1 do
    if TObject(Items[i]) is aPageClass then
      result := i;
end;
//------------------------------------------------------------------------------
Function TPageList.AddPageByClass(aPageClass: TBasePageClass): TBasePage;
begin
  result := aPageClass.Create;
  Add(result);
end;
//------------------------------------------------------------------------------
Function TPageList.DeletePageByClass(aPageClass: TBasePageClass; aShouldFree: Boolean = false): Boolean;
var
  PageIndex: Integer;
  Page: TBasePage;
begin
  PageIndex := GetIndexByClass(aPageClass);
  result := PageIndex > -1;
  if result then
  begin
    if aShouldFree then
      Page := TBasePage(Items[PageIndex]);

    Delete(PageIndex);

    if aShouldFree then
      FreeAndNil(Page);
  end;
end;
//------------------------------------------------------------------------------
Function TPageList.DeletePage(var aPage: TBasePage; aShouldFree: Boolean = false): Boolean;
var
  PageIndex: Integer;
begin
  PageIndex := IndexOf(aPage);
  result := PageIndex > -1;
  if result then
  begin
    Delete(PageIndex);

    if aShouldFree then
      FreeAndNil(aPage);
  end;
end;
//------------------------------------------------------------------------------
end.
